/*
 * Copyright (c) 2003-2006,2008,2010-2012 Apple Inc. All Rights Reserved.
 * 
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 * 
 * certExtensionTemplates.cpp - libnssasn1 structs and templates for cert and 
 *                              CRL extensions
 *
 */
 
#include "certExtensionTemplates.h"
#include "SecAsn1Templates.h"
#include <stddef.h>

/* Basic Constraints */
const SecAsn1Template kSecAsn1BasicConstraintsTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_BasicConstraints) },
    { SEC_ASN1_BOOLEAN | SEC_ASN1_OPTIONAL, 
	  offsetof(NSS_BasicConstraints,cA) },
    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL,
	  offsetof(NSS_BasicConstraints, pathLenConstraint) },
    { 0, }
};

/* Authority Key Identifier */

/* signed integer - SEC_ASN1_SIGNED_INT state gets lost
 * in SEC_ASN1_CONTEXT_SPECIFIC processing */
const SecAsn1Template kSecAsn1SignedIntegerTemplate[] = {
    { SEC_ASN1_INTEGER | SEC_ASN1_SIGNED_INT, 0, NULL, sizeof(SecAsn1Item) }
};

const SecAsn1Template kSecAsn1AuthorityKeyIdTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_AuthorityKeyId) },
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 
	  SEC_ASN1_POINTER | 0, 
	  offsetof(NSS_AuthorityKeyId,keyIdentifier),
	  kSecAsn1OctetStringTemplate },
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
	                      SEC_ASN1_CONTEXT_SPECIFIC | 1, 
	  offsetof(NSS_AuthorityKeyId,genNames), 
	  kSecAsn1GeneralNamesTemplate },
	/* serial number is SIGNED integer */
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 2,
	  offsetof(NSS_AuthorityKeyId,serialNumber), 
	  kSecAsn1SignedIntegerTemplate},
	{ 0 }
};

/* Certificate policies */
const SecAsn1Template kSecAsn1PolicyQualifierTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_PolicyQualifierInfo) },
    { SEC_ASN1_OBJECT_ID,  
	  offsetof(NSS_PolicyQualifierInfo,policyQualifierId) },
	{ SEC_ASN1_ANY, offsetof(NSS_PolicyQualifierInfo, qualifier) },
	{ 0 }
};

const SecAsn1Template kSecAsn1PolicyInformationTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_PolicyInformation) },
    { SEC_ASN1_OBJECT_ID,  
	  offsetof(NSS_PolicyInformation,certPolicyId) },
	{ SEC_ASN1_SEQUENCE_OF | SEC_ASN1_OPTIONAL,
	  offsetof(NSS_PolicyInformation,policyQualifiers),
	  kSecAsn1PolicyQualifierTemplate },
	{ 0 }
};

const SecAsn1Template kSecAsn1CertPoliciesTemplate[] = {
	{ SEC_ASN1_SEQUENCE_OF,
	  offsetof(NSS_CertPolicies,policies),
	  kSecAsn1PolicyInformationTemplate },
	{ 0 }
};

/* CRL Distribution Points */

/*
 * NOTE WELL: RFC2459, and all the documentation I can find, claims that
 * the tag for the DistributionPointName option (tag 0) of a 
 * DistributionPoint is IMPLICIT and context-specific. However this
 * is IMPOSSIBLE - since the underlying type (DistributionPointName)
 * also relies upon context-specific tags to resolve a CHOICE. 
 * The real world indicates that the tag for the DistributionPoint option
 * is indeed EXPLICIT. Examination of many certs' cRLDistributionPoints
 * extensions shows this, and the NSS reference code also specifies
 * an EXPLICIT tag for this field. 
 */
const SecAsn1Template kSecAsn1DistributionPointTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_DistributionPoint) },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
	  SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
	  offsetof(NSS_DistributionPoint,distPointName), 
	  kSecAsn1PointerToAnyTemplate },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1,
	  offsetof(NSS_DistributionPoint,reasons), kSecAsn1BitStringTemplate},
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
						  SEC_ASN1_CONSTRUCTED | 2,
	  offsetof(NSS_DistributionPoint, crlIssuer), 
	  kSecAsn1GeneralNamesTemplate
	},
	{ 0 }
};

const SecAsn1Template kSecAsn1CRLDistributionPointsTemplate[] = {
	{ SEC_ASN1_SEQUENCE_OF,
	  offsetof(NSS_CRLDistributionPoints,distPoints),
	  kSecAsn1DistributionPointTemplate },
	{ 0 }
};


/*
 * These are the context-specific targets of the DistributionPointName
 * option.
 */
const SecAsn1Template kSecAsn1DistPointFullNameTemplate[] = {
    {SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0,
	offsetof (NSS_GeneralNames,names), kSecAsn1GeneralNamesTemplate}
};

const SecAsn1Template kSecAsn1DistPointRDNTemplate[] = {
    {SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, 
	offsetof (NSS_RDN,atvs), kSecAsn1RDNTemplate}
};
	 
/*
 * Issuing distribution points
 *
 * Although the spec says that the DistributionPointName element
 * is context-specific, it must be explicit because the underlying
 * type - a DistributionPointName - also relies on a context-specific
 * tags to resolve a CHOICE.
 */

/* kludge: ASN decoder doesn't handle 
 * SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER
 * very well... */
static const SecAsn1Template kSecAsn1OptBooleanTemplate[] = {
    { SEC_ASN1_BOOLEAN | SEC_ASN1_OPTIONAL, 0, NULL, sizeof(SecAsn1Item) }
};

static const SecAsn1Template kSecAsn1OptBitStringTemplate[] = {
    { SEC_ASN1_BIT_STRING | SEC_ASN1_OPTIONAL, 0, NULL, sizeof(SecAsn1Item) }
};

const SecAsn1Template kSecAsn1IssuingDistributionPointTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_IssuingDistributionPoint) },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 
	  SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
	  offsetof(NSS_IssuingDistributionPoint,distPointName), 
	  kSecAsn1PointerToAnyTemplate },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER | 1,
	  offsetof(NSS_IssuingDistributionPoint,onlyUserCerts), 
	  kSecAsn1OptBooleanTemplate},
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER | 2,
	  offsetof(NSS_IssuingDistributionPoint,onlyCACerts), 
	  kSecAsn1OptBooleanTemplate},
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER | 3,
	  offsetof(NSS_IssuingDistributionPoint,onlySomeReasons), 
	  kSecAsn1OptBitStringTemplate},
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER | 4,
	  offsetof(NSS_IssuingDistributionPoint,indirectCRL), 
	  kSecAsn1OptBooleanTemplate},
	{ 0 }
};


/* 
 * Authority Information Access and Subject Information Access.
 */
const SecAsn1Template kSecAsn1AccessDescriptionTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_AccessDescription) },
    { SEC_ASN1_OBJECT_ID,  
	  offsetof(NSS_AccessDescription,accessMethod) },
	/* 
	 * NSS encoder just can't handle direct inline of an NSS_GeneralName here.
	 */
    { SEC_ASN1_ANY,
      offsetof(NSS_AccessDescription, encodedAccessLocation) },
	{ 0 }
};

const SecAsn1Template kSecAsn1AuthorityInfoAccessTemplate[] = {
    { SEC_ASN1_SEQUENCE_OF, 
	  offsetof(NSS_AuthorityInfoAccess,accessDescriptions), 
	  kSecAsn1AccessDescriptionTemplate, 
	  sizeof(NSS_AuthorityInfoAccess) }
};

/*
 * Qualified Certificate Statements templates.
 *
 * This is the NSS_QC_Statement.info when NSS_QC_Statement.statementId
 * is CSSMOID_OID_QCS_SYNTAX_V2.
 */
const SecAsn1Template kSecAsn1SemanticsInformationTemplate[] = {
    { SEC_ASN1_SEQUENCE,
		0, NULL, sizeof(NSS_SemanticsInformation) },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_POINTER,
		offsetof(NSS_SemanticsInformation,semanticsIdentifier), 
		kSecAsn1ObjectIDTemplate },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_POINTER,
		offsetof(NSS_SemanticsInformation, nameRegistrationAuthorities), 
		kSecAsn1GeneralNamesTemplate },
	{ 0 }
};
		
const SecAsn1Template kSecAsn1QC_StatementTemplate[] = {
    { SEC_ASN1_SEQUENCE,
		0, NULL, sizeof(NSS_QC_Statement) },
    { SEC_ASN1_OBJECT_ID,  
		offsetof(NSS_QC_Statement,statementId) },
    { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL,
		offsetof(NSS_QC_Statement, info) },
	{ 0 }
};

const SecAsn1Template kSecAsn1QC_StatementsTemplate[] = {
    { SEC_ASN1_SEQUENCE_OF, 
		offsetof(NSS_QC_Statements,qcStatements), 
		kSecAsn1QC_StatementTemplate, 
		sizeof(NSS_QC_Statements) }
};

/*
 * NameConstraints templates
 */
const SecAsn1Template kSecAsn1GeneralSubtreeTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_GeneralSubtree) },
	{ SEC_ASN1_SEQUENCE,
	  offsetof(NSS_GeneralSubtree,base), 
	  kSecAsn1GeneralNamesTemplate },	
	{ SEC_ASN1_INTEGER,
	  offsetof(NSS_GeneralSubtree,minimum) },
	{ SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL,
	  offsetof(NSS_GeneralSubtree,maximum) },
    { 0, }
};

const SecAsn1Template kSecAsn1GeneralSubtreesTemplate[] = {
	{ SEC_ASN1_SEQUENCE_OF,
	  offsetof(NSS_GeneralSubtrees,subtrees),
	  kSecAsn1GeneralSubtreeTemplate },
	{ 0 }
};

const SecAsn1Template kSecAsn1NameConstraintsTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_NameConstraints) },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
	  SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
	  offsetof(NSS_NameConstraints,permittedSubtrees), 
	  kSecAsn1GeneralSubtreesTemplate },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
	  SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 1,
	  offsetof(NSS_NameConstraints,excludedSubtrees), 
	  kSecAsn1GeneralSubtreesTemplate },
	{ 0 }
};

/*
 * PolicyMappings templates
 */
const SecAsn1Template kSecAsn1PolicyMappingTemplate[] = {
    { SEC_ASN1_SEQUENCE,
		0, NULL, sizeof(NSS_PolicyMapping) },
    { SEC_ASN1_OBJECT_ID,  
		offsetof(NSS_PolicyMapping,issuerDomainPolicy) },
    { SEC_ASN1_OBJECT_ID,  
		offsetof(NSS_PolicyMapping,subjectDomainPolicy) },
	{ 0 }
};

const SecAsn1Template kSecAsn1PolicyMappingsTemplate[] = {
	{ SEC_ASN1_SEQUENCE_OF,
	  offsetof(NSS_PolicyMappings,policyMappings),
	  kSecAsn1PolicyMappingTemplate },
	{ 0 }
};

/*
 * PolicyConstraints templates
 */
const SecAsn1Template kSecAsn1PolicyConstraintsTemplate[] = {
    { SEC_ASN1_SEQUENCE,
	  0, NULL, sizeof(NSS_PolicyConstraints) },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
	  SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
	  offsetof(NSS_PolicyConstraints,requireExplicitPolicy) },
	{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
	  SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 1,
	  offsetof(NSS_PolicyConstraints,inhibitPolicyMapping) },
	{ 0 }
};


